#include <iostream>
#include <fstream>
#include "mpegts_demuxer.h"
#include "h264/h264bsd_decoder.h"
#include "mpeg2/mpeg2_internal.h"
#include "mpeg2/YUV_TO_BMP.h"
static mpeg2dec_t mpeg2dec;
static vo_open_t * output_open = NULL;
vo_instance_t * output = NULL;
//AAC (ADTS) audio
#define TYPE_AUDIO 0x0f
//H.264 video
#define TYPE_VIDEO_H264 0x1b
//H.265 video
#define TYPE_VIDEO_H265 0x24
//MPGE-II video
#define TYPE_VIDEO_MPGE2 0x02

using namespace mpegts;

MpegTsDemuxer* gDemuxer;

int aFrameCounter = {1};
int vFrameCounter = {1};

static const double S_PI = 3.14159265358979323846;
#define scos(x)         cos((double)(x))
#define stan(x)         tan((double)(x))
#define ssqrt(x)        sqrt((double)(x))
#define ET_SIZE 300

uint8_t packet[188] = {0};
storage_t* pstorage_t(nullptr);
SimpleBuffer in;

static int count = 0;

void write_bmpheader(unsigned char *bitmap, int offset, int bytes, int value)
{
        int i;
        for (i = 0; i < bytes; i++)
            bitmap[offset + i] = (value >> (i << 3)) & 0xFF;
}
unsigned char *convertToBmp(unsigned char *inputImg, int width, int height, int *ouputSize)
{
        /*create a bmp format file*/
        int bitmap_x = (int)ceil((double)width * 3 / 4) * 4;
        unsigned char *bitmap = (unsigned char*)malloc(sizeof(unsigned char)*height*bitmap_x + 54);

        bitmap[0] = 'B';
        bitmap[1] = 'M';
        write_bmpheader(bitmap, 2, 4, height*bitmap_x + 54); //whole file size
        write_bmpheader(bitmap, 0xA, 4, 54); //offset before bitmap raw data
        write_bmpheader(bitmap, 0xE, 4, 40); //length of bitmap info header
        write_bmpheader(bitmap, 0x12, 4, width); //width
        write_bmpheader(bitmap, 0x16, 4, height); //height
        write_bmpheader(bitmap, 0x1A, 2, 1);
        write_bmpheader(bitmap, 0x1C, 2, 24); //bit per pixel
        write_bmpheader(bitmap, 0x1E, 4, 0); //compression
        write_bmpheader(bitmap, 0x22, 4, height*bitmap_x); //size of bitmap raw data

        for (int i = 0x26; i < 0x36; i++)
            bitmap[i] = 0;

        int k = 54;
        for (int i = height - 1; i >= 0; i--) {
            int j;
            for (j = 0; j < width; j++) {
                int index = i*width + j;
                for (int l = 0; l < 3; l++)
                    bitmap[k++] = inputImg[index];
            }
            j *= 3;
            while (j < bitmap_x) {
                bitmap[k++] = 0;
                j++;
            }
        }

        *ouputSize = k;
        return bitmap;
}
void saveToBmp(unsigned char *inputImg, int width, int height, char *outputFileName)
{
        int size;
        unsigned char *bmp = convertToBmp(inputImg, width, height, &size);
        FILE *fp = fopen(outputFileName, "wb+");
        if (fp == NULL) {
        // sprintf(errorText, "Could not open file: %s", outputFileName);
        // errorMsg(errorText);
        std::cout << "Could not open file:"<<outputFileName << std::endl;
        }
        fwrite(bmp, 1, size, fp);
        fclose(fp);
        free(bmp);
}
void readSequence(unsigned char *frames,unsigned int width,unsigned int height)
{
    //Test start
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            //使用公式生成像素数据
            float pu0 = (float)((2.0*(x + 0.5)) / width - 1.0);
            float pv0 = (float)((2.0*(y + 0.5)) / height - 1.0);

            double tu0 = stan(pu0*S_PI / 4.0);
            double tv0 = stan(pv0*S_PI / 4.0);
            double value= 1.0 / (scos(pu0*S_PI / 4.0)*scos(pu0*S_PI / 4.0)*scos(pv0*S_PI / 4.0)*scos(pv0*S_PI / 4.0) * (tu0*tu0 + tv0*tv0 + 1.0) * ssqrt(tu0*tu0 + tv0*tv0 + 1.0));

            //将值从(0，1)放大到(0，255)
            value= 255.0*value;
            //将值从(128，255)放大到(0，255),增加图像对比度
            frames[y*width + x] = 2.0*value- 255.0;
        }
    }
}

extern "C" {
    extern void outFrame(char *,int size);
    extern void outYUV(uint8_t *,uint8_t *,uint8_t *,int width,int height);
    void setPacket(int index,unsigned char value){
        packet[index] = value;
    }

    void dmxOutput(const EsFrame &esFrame) {
        //std::cout << esFrame.mData->size() << std::endl;
        //std::cout << (short)esFrame.mStreamType << std::endl;
        if (esFrame.mStreamType == TYPE_VIDEO_H264) {
            //outFrame((char *)esFrame.mData->data(),esFrame.mData->size());
            //std::cout << esFrame.mData->size() << std::endl;
         /* u8** pic = nullptr;
            u32* width = nullptr;
            u32* height = nullptr;
            u32 flag = h264bsdDecode(pstorage_t,esFrame.mData->data(),esFrame.mData->size(),pic,width,height);
            if(flag == 1){
                unsigned char *inputImg = (unsigned char *)malloc(esFrame.mData->size());
                readSequence(inputImg,*width,*height);
                char name[] = {"F:/tmp.bmp"};
                saveToBmp(inputImg, *width, *height, name);
                free(inputImg);
            }*/
        }
        if (esFrame.mStreamType == TYPE_VIDEO_MPGE2) {
            uint8_t * end = esFrame.mData->data() + esFrame.mData->size();
            std::cout << count << std::endl;
            count++;
            /*int num_frames = mpeg2_decode_data (&mpeg2dec, esFrame.mData->data(), end);
            std::cout << num_frames << std::endl;
            if(num_frames > 0){
                //char name[] = {"F:/tmp.bmp"};
                vo_frame_t * frame = mpeg2dec.picture->current_frame;
                //outYUV(frame->base[0],frame->base[1],frame->base[2],mpeg2dec.picture->coded_picture_width,mpeg2dec.picture->coded_picture_height);
                //mpeg2_drop(&mpeg2dec,1);
               //unsigned char * rgb_buf = (unsigned char *)malloc(640 * 384 * 3);
               //fn_Convert_Yuv(rgb_buf,frame->base[0],frame->base[1],frame->base[2],640, 384);
               //fn_Make_Bmp(rgb_buf,name,640, 384);
               //free(rgb_buf);
               count++;
            }
            if(count == 24){
                    //mpeg2_reset(&mpeg2dec,output);
                    count = 0;
                    std::cout << "mpeg2_reset" << std::endl;
            }
           */
        }
    }
    void init(){
        gDemuxer = new MpegTsDemuxer();
        gDemuxer->esOutCallback = std::bind(&dmxOutput, std::placeholders::_1);
        //return &packet[0];
    }
    void demuxer(){
        in.append(packet, 188);
        gDemuxer->decode(in);
        //std::cout << "demuxer!\n" << std::endl;
    }
    void destory(){
        mpeg2_close (&mpeg2dec);
        vo_close (output);
        std::cout << "Bye!\n" << std::endl;
    }
}

int main(int, char**){
    vo_driver_t * drivers = vo_drivers();
    output_open = drivers[0].open;
    output = output_open();
    mpeg2_init (&mpeg2dec, 0, output);
    
   // std::cout << "Hello!\n" << std::endl;
    //pstorage_t = h264bsdAlloc();
    //h264bsdInit(pstorage_t, 0);

    init();

    /*
    std::ifstream ifile("F:/example.ts", std::ios::binary | std::ios::in);
    while (!ifile.eof()) {
        ifile.read((char*)&packet[0], 188);
        demuxer();
    }
    ifile.close();
    mpeg2_close (&mpeg2dec);
    vo_close (output);
    */
    std::cout << "Hello, from  tsdemux!\n" << std::endl;

}





    

    
